<!DOCTYPE html>
<!--官网rect使用教程  @link https://konvajs.org/docs/shapes/Rect.html -->
<!--官网rect.size()api  @link  https://konvajs.org/api/Konva.Rect.html#size__anchor-->
<!--官网 Transformer api http://konvajs-doc.bluehymn.com/docs/select_and_transform/Keep_Ratio.html -->
<!--官网 Konva.Group api https://konvajs.org/api/Konva.Group.html -->
<!--等比缩放图片 http://konvajs-doc.bluehymn.com/docs/select_and_transform/Keep_Ratio.html -->

<!--官网缩放显示图片案例（复用代码） @link https://konvajs.org/docs/sandbox/Scale_Image_To_Fit.html -->
<!--csdn博文 磁吸效果（无关，感兴趣看一下） https://blog.csdn.net/xachary2/article/details/137841512 -->

<html>

<head>
    <script src="./konva@9.3.12.min.js"></script>
    <meta charset="utf-8" />
    <title>Konva 绘制矩形选区</title>
    <style>
        html,
        body {
            margin: 0;
            padding: 0;
            /* width: 100%;
            height: 100%;
            background-color: white; */
            width: 1080px;
            height: 2400px;
            /* background-color: pink; */
        }

        body {
            background-color: pink;
            position: relative;
        }

        .op_box {
            position: absolute;
            height: 100px;
            top: 40px;
            width: 100%;
            padding: 0 20px;
            box-sizing: border-box;
            /* background-color: yellow; */

            display: flex;
            align-items: center;
            justify-content: flex-end;
        }

        .op_box button {
            font-size: 40px;
            color: blue;
            margin-left: 20px;
        }

        #btn_start2,
        #btn_restart,
        #btn_prev_step,
        #btn_quit,
        #btn_ok {
            display: none;
        }
    </style>
</head>

<body>
    <div id="container"></div>
    <div class="op_box">
        <button id="btn_start1">选择背包区域</button>
        <button id="btn_prev_step">上一步</button>
        <button id="btn_start2">选择符石案例区域</button>
        <button id="btn_restart">重绘</button>
        <button id="btn_quit">退出</button>
        <button id="btn_ok">完成</button>
    </div>
    <script>
        /**
         * 问题
         *   #3788 node.on(),只有两个参数，没法取消事件捕获；可以给layer2建一个透明的节点，撑满它。实现超区域结束move事件
         *          判断超区还要小心碰到绘制的rect2，判断条件改好。这里如果用事件冒泡不合适，因为我们监听的是layer2
         *              
         * 
         */
        /**
         * @description 操作步骤
         * @constant 
         * @readonly
         * @enum {number}
         */
        const OP_STEP = {
            /** 初始状态 */
            A: 0,
            /** 绘制背包区域完成 */
            B: 1,
            /** 绘制符石案例区域 */
            C: 2,
        };

        let stage = null;
        let layer1 = new Konva.Layer();
        let layer2 = new Konva.Layer();

        let is_drawing_bag_area = false;
        let is_drawing_rune_area = false;

        const outer_id = "outer"; // #3788
        const image2_id = "image2"; // #3788



        let curr_step = OP_STEP.A;

        // const rect_stroke_color = "red";
        const rect_stroke_color = "rgba(0,255,255,255)";
        const rect_stroke_color2 = "rgba(255,0,125,255)";
        let text = new Konva.Text({
            x: 10,
            y: 10,
            fontFamily: 'Calibri',
            fontSize: 24,
            text: '我是文本',
            // fill: 'white',
            fill: 'red',
        });
        let text2 = new Konva.Text({
            x: 10,
            y: 10,
            fontFamily: 'Calibri',
            fontSize: 24,
            text: '我是文本',
            // fill: 'white',
            fill: 'red',
        });

        let drawing_rect1 = false;
        let drawing_rect2 = false;
        let rect1 = null;
        let rect2 = null;

        let bagRect = null;
        let runeRect = null;
        let start_point = null;
        let start_point2 = null;

        let image2_c = null; // 备份的image2,调试显示用
        // Konva.Vector2d

        /**
         * @function 
         * @description 调试用，快速切换到指定步骤
         * @param { OP_STEP }  currStep
         */
        function debugStep(currStep) {
            if (currStep == OP_STEP.B) {
                curr_step = OP_STEP.B;
                o_btn_restart.style.display = "none";
                o_btn_quit.style.display = "none";
                o_btn_ok.style.display = "none";

                o_btn_prev_step.style.display = "block";
                o_btn_start1.style.display = "none";
                o_btn_start2.style.display = "block";

                bagRect = {
                    x: 231,
                    y: 1282,
                    width: 734,
                    height: 596,
                }

                let img1 = layer1.findOne('#img1');
                let img2 = img1.clone();
                img2.toImage({
                    callback(img) {
                        // 有问题，不像这样写
                        // console.log("xxx", img1);// htmlEl
                        let sc_w = img.width;
                        let sc_h = img.height;
                        let image = new Konva.Image({
                            id: image2_id,
                            image: img,
                            width: sc_w,
                            height: sc_h,
                            x: 180,
                            y: 180,
                            name: 'image2',
                            draggable: true, // 拖拽是图片节点的功能
                            // opacity: 0.1
                        });
                        layer2.add(image);
                        image2_c = image.clone();
                        image2_c.id("image2_c");

                        let tr = new Konva.Transformer({
                            node: image,
                            id: "tr_bag", // 无效
                            keepRatio: true,
                            // flipEnabled 好像可以裁剪
                            rotateEnabled: false, // 禁止旋转
                            enabledAnchors: ['top-left', 'top-right', 'bottom-left', 'bottom-right']
                        });
                        // console.log(tr);
                        layer2.add(tr);
                        // layer.draw();
                    },
                    mimeType: "image/jpeg",
                    x: bagRect.x,
                    y: bagRect.y,
                    width: bagRect.width,
                    height: bagRect.height,
                    quality: 0.5, // 0-1
                    pixelRatio: 1, // 
                    imageSmoothingEnabled: false,
                });


                layer1.hide();
                layer2.show();
            }
        }

        Konva.Image.fromURL(
            // 'https://konvajs.org/assets/darth-vader.jpg',
            '../screenshot1.jpg',
            (img) => {
                let sc_w = img.width();
                let sc_h = img.height();
                console.log("img:", sc_w, sc_h);
                img.setAttrs({
                    width: sc_w,
                    height: sc_h,
                    x: 0,
                    y: 0,
                    name: 'image', // 相等于 class 可以以空格分隔，多个name
                    id: 'img1', // 相等于id
                    draggable: false,
                    // opacity: 0.1
                });
                layer1.add(img);
                layer1.add(text);

                // layer2.add(img);// 直接添加相当于换父节点
                let outer = img.clone().opacity(0);
                outer.id(outer_id);
                layer2.add(outer); // #3788 防止事件直接捕获到img2
                layer2.add(text2);


                stage = new Konva.Stage({
                    container: 'container',
                    width: sc_w, // window.innerWidth
                    height: sc_h, // window.innerHeight
                });


                stage.add(layer1);
                stage.add(layer2);
                layer2.hide();
                // console.log("layer1: ", layer1.width(), layer1.height()); //1080 2400

                debugStep(OP_STEP.B);
            }
        );


        function writeMessage(message) {
            text.text(message);
        }

        function writeMessage2(message) {
            text2.text(message);
        }


        function touchStartHandler1() {
            var touchPos = stage.getPointerPosition();
            var x = touchPos.x;
            var y = touchPos.y;

            drawing_rect1 = true;
            start_point = {
                x,
                y
            };
            writeMessage('Touchstart layer1');
        }

        function touchMoveHandler1() {
            var touchPos = stage.getPointerPosition();
            // var x = touchPos.x - 190;
            // var y = touchPos.y - 40;
            var x = touchPos.x;
            var y = touchPos.y;
            writeMessage('x: ' + x + ', y: ' + y);
            changeRect1(x, y);
        }

        function changeRect1(x, y) {
            if (drawing_rect1) {

                let offset_x = Math.abs(start_point.x - x);
                let offset_y = Math.abs(start_point.y - y);
                if (offset_x > 20 || offset_y > 20) {
                    if (!rect1) {
                        // console.log("初次创建rect");
                        rect1 = new Konva.Rect({
                            x: start_point.x,
                            y: start_point.y,
                            width: offset_x,
                            height: offset_y,
                            fill: '',
                            stroke: rect_stroke_color,
                            strokeWidth: 2,
                        });
                        // add the shape to the layer1
                        layer1.add(rect1);
                        // rect1.draw();
                    } else {
                        rect1.size({
                            width: offset_x,
                            height: offset_y,
                        })
                    }
                }


            }
        }

        function clearAndOff1() {
            drawing_rect1 = false;
            start_point = null;
            layer1.off('touchmove');
            layer1.off('touchstart');
            layer1.off('touchend');
            rect1 && rect1.destroy();
            rect1 = null;
        }


        function touchEndHandler1() {
            writeMessage('Touchend layer1');

            drawing_rect1 = false;
            start_point = null;
            layer1.off('touchmove');
            layer1.off('touchstart');
            layer1.off('touchend');


            o_btn_ok.style.display = "block";
            o_btn_restart.style.display = "block";

        }

        function touchStartHandler2(evt) {
            console.log("touchStart", evt.target.id());
            // console.log("touchStart");
            if (evt.target.id() != image2_id) {
                console.log("未在图片内，退出");
                return;
            }
            // evt.currentTarget (不会用 ，拿不到id), evt.target
            // var target = evt.target; // 事件委托
            // console.log("start,target:", target);
            // if(){

            // }
            var touchPos = stage.getPointerPosition();

            var x = touchPos.x;
            var y = touchPos.y;

            drawing_rect2 = true;
            start_point2 = {
                x,
                y
            };
            writeMessage2('Touchstart bag_area_img');
        }

        function touchMoveHandler2(evt) {
            // console.log("touchMove",evt.currentTarget && evt.currentTarget.name());
            // console.log("touchMove");
            // var target = evt.target; // 事件委托
            // console.log("move，target:", target); // 事件委托
            if (!drawing_rect2) {
                console.log("未开始绘制，退出");
                return;
            }
            // console.log("target:id", evt.target.id());
            // console.log("currentTarget:id", evt.currentTarget.id());
            // console.log("currentTarget", evt.currentTarget);
            // if (evt.target.id() != image2_id) {// #3788
            if (evt.target.id() == outer_id) { // #3788
                console.log("超出图片外");
                drawing_rect2 = false;
                start_point2 = null;

                // console.log("rect2", rect2);
                getRealRect2();

                o_btn_ok.style.display = "block";
                o_btn_restart.style.display = "block";

                layer2.off('touchmove');
                layer2.off('touchstart');
                layer2.off('touchend');

                console.log("立即停止绘制");
                return;
            }
            var touchPos = stage.getPointerPosition();

            var x = touchPos.x;
            var y = touchPos.y;
            writeMessage2('x: ' + x + ', y: ' + y);
            changeRect2(x, y);
        }

        function changeRect2(x, y) {
            if (drawing_rect2) {

                let offset_x = Math.abs(start_point2.x - x);
                let offset_y = Math.abs(start_point2.y - y);
                if (offset_x > 20 || offset_y > 20) {
                    if (!rect2) {
                        // console.log("初次创建rect");
                        rect2 = new Konva.Rect({
                            id: "rect2",
                            x: start_point2.x,
                            y: start_point2.y,
                            width: offset_x,
                            height: offset_y,
                            fill: '',
                            stroke: rect_stroke_color2,
                            strokeWidth: 2,
                        });
                        // add the shape to the layer1
                        layer2.add(rect2);

                        // bag_area_img.add(rect2);// node，没有add方法
                    } else {
                        rect2.size({
                            width: offset_x,
                            height: offset_y,
                        })
                    }
                }


            }
        }

        function clearAndOff2() {
            drawing_rect2 = false;
            start_point2 = null;

            layer2.off('touchmove');
            layer2.off('touchstart');
            layer2.off('touchend');
            rect2 && rect2.destroy();
            rect2 = null;
        }


        function touchEndHandler2(evt) {
            // var target = evt.target; // 事件委托
            // console.log("touchEnd",evt.currentTarget);
            console.log("touchEnd");
            // console.log("end,target:", target);
            // writeMessage2('Touchend bag_area_img');
            if (!drawing_rect2) {
                console.log("未开始绘制，退出");
                return;
            }
            drawing_rect2 = false;
            start_point2 = null;

            // console.log("rect2", rect2);
            getRealRect2();


            o_btn_ok.style.display = "block";
            o_btn_restart.style.display = "block";


            // bag_area_img.off('touchmove');
            // bag_area_img.off('touchstart');
            // bag_area_img.off('touchend');

            layer2.off('touchmove');
            layer2.off('touchstart');
            layer2.off('touchend');
        }

        /**
         * @function 
         * @description 获取选中符石相对选中背包区域的真实Rect(本身它是可拖拽、缩放的)
         */
        function getRealRect2() {
            /*** @todo 到这步发现个问题，一开始就知道node没有add方法，我应该将image2和rect放在同一个group里面操作，这样取相对坐标方便点**/
            // 但写到现在再改的话，改动有点多，就直接计算吧

            // console.log("rect2", rect2);
            // let tr = layer2.findOne('#tr_bag');

            let bag_area_img = layer2.findOne("#" + image2_id);

            // let pos_img = bag_area_img.position();
            let pos_img = bag_area_img.getAbsolutePosition();
            console.log(pos_img.x, pos_img.y);

            // rect2 position relative to bag_area_img
            let x = rect2.getAttr('x') - pos_img.x;
            let y = rect2.getAttr('y') - pos_img.y;
            // console.log(x, y, bagRect);
            // console.log(bag_area_img.scale());// 缩放比例
            let ratio_scale = bag_area_img.scale().x; // 取x,y值都行，因为是等比缩放
            console.log(x, y, ratio_scale);

            /**@todo 浮点数计算误差*/
            runeRect = {
                x: Math.ceil(x / ratio_scale),
                y: Math.ceil(y / ratio_scale),
                width: Math.floor(rect2.width() / ratio_scale),
                height: Math.floor(rect2.height() / ratio_scale),
            };

            console.log(runeRect);
            showPaintedImage2();
        }

        /**
         * @function 
         * @description 调试用，用于展示绘制选区在原来图片上是否正常
         */
        function showPaintedImage2() {
            let group = new Konva.Group({
                x: 150,
                y: 1000,
                width: image2_c.width(),
                height: image2_c.height(),
            });

            layer2.add(group);
            group.add(image2_c);
            image2_c.position({
                x: 0,
                y: 0
            });

            let rect = new Konva.Rect({
                id: "image2_c_rect",
                x: runeRect.x,
                y: runeRect.y,
                width: runeRect.width,
                height: runeRect.height,
                fill: '',
                stroke: rect_stroke_color2,
                strokeWidth: 2,
            });
            group.add(rect);
        }


        let o_btn_start1 = document.getElementById("btn_start1");
        let o_btn_start2 = document.getElementById("btn_start2");
        let o_btn_prev_step = document.getElementById("btn_prev_step");
        let o_btn_restart = document.getElementById("btn_restart");
        let o_btn_quit = document.getElementById("btn_quit");
        let o_btn_ok = document.getElementById("btn_ok");

        // add button event bindings
        o_btn_start1.addEventListener(
            'click',
            function (event) {
                // event.stopPropagation();
                // event.preventDefault();
                console.log("btn_start1 click");


                o_btn_start1.style.display = "none";

                o_btn_quit.style.display = "block";

                layer1.on('touchmove', touchMoveHandler1);
                layer1.on('touchstart', touchStartHandler1);
                layer1.on('touchend', touchEndHandler1);

                return false;

            },
            false
        );



        o_btn_start2.addEventListener(
            'click',
            function (event) {
                // event.stopPropagation();
                // event.preventDefault();
                console.log("btn_start2 click");

                o_btn_start2.style.display = "none";
                o_btn_prev_step.style.display = "none";

                // o_btn_restart.style.display = "block";
                o_btn_quit.style.display = "block";
                // o_btn_ok.style.display = "block";

                // 绘制过程中取消缩放，拖拽
                let tr = layer2.findOne('#tr_bag');
                tr.resizeEnabled(false);

                let bag_area_img = layer2.findOne("#" + image2_id);
                bag_area_img.draggable(false);

                clearAndOff2();

                layer2.on('touchmove', touchMoveHandler2);
                layer2.on('touchstart', touchStartHandler2);
                layer2.on('touchend', touchEndHandler2); // on只有两个参数 没法取消事件捕获
                // console.log("layer2:",layer2.width(), layer2.height(),layer2.position());


                return false;

            },
            false
        );

        o_btn_prev_step.addEventListener(
            'click',
            function (event) {
                // event.stopPropagation();
                // event.preventDefault();
                console.log("btn_prev_step click");
                curr_step = OP_STEP.A;
                o_btn_prev_step.style.display = "none";
                o_btn_start2.style.display = "none";
                layer1.show();
                layer2.destroyChildren();
                layer2.hide();

                o_btn_restart.style.display = "block";
                o_btn_quit.style.display = "block";
                o_btn_ok.style.display = "block";



                return false;

            },
            false
        );


        o_btn_restart.addEventListener(
            'click',
            function (event) {
                // event.stopPropagation();
                // event.preventDefault();
                console.log("o_btn_restart click");
                o_btn_ok.style.display = "none";
                o_btn_restart.style.display = "none";

                if (curr_step == OP_STEP.A) {
                    clearAndOff1();
                    layer1.on('touchmove', touchMoveHandler1);
                    layer1.on('touchstart', touchStartHandler1);
                    layer1.on('touchend', touchEndHandler1);


                }


                return false;

            },
            false
        );
        o_btn_quit.addEventListener(
            'click',
            function (event) {
                // event.stopPropagation();
                // event.preventDefault();
                console.log("o_btn_quit click");

                o_btn_restart.style.display = "none";
                o_btn_quit.style.display = "none";
                o_btn_ok.style.display = "none";

                if (curr_step == OP_STEP.A) {
                    o_btn_start1.style.display = "block";

                    clearAndOff1();

                } else if (curr_step == OP_STEP.B) {
                    o_btn_start2.style.display = "block";
                    o_btn_prev_step.style.display = "block";
                }

                return false;

            },
            false
        );
        o_btn_ok.addEventListener(
            'click',
            function (event) {
                // event.stopPropagation();
                // event.preventDefault();
                console.log("o_btn_ok click", rect1);
                // console.log("o_btn_ok click");

                if (curr_step == OP_STEP.A) {
                    curr_step = OP_STEP.B;
                    o_btn_restart.style.display = "none";
                    o_btn_quit.style.display = "none";
                    o_btn_ok.style.display = "none";

                    o_btn_prev_step.style.display = "block";
                    o_btn_start2.style.display = "block";



                    // 拿到选区
                    let x = Math.floor(rect1.getAttr('x'));
                    let y = Math.floor(rect1.getAttr('y'));
                    let width = Math.ceil(rect1.getAttr('width'));
                    let height = Math.ceil(rect1.getAttr('height'));

                    bagRect = {
                        x,
                        y,
                        width,
                        height
                    };
                    console.log(bagRect);

                    // 根据选区生成图片并显示到layer2

                    // let img1 = layer1.find('#img1');// [ve]
                    let img1 = layer1.findOne('#img1');
                    let img2 = img1.clone();
                    img2.toImage({
                        callback(img) {
                            // 有问题，不像这样写
                            // console.log("xxx", img1);// htmlEl
                            let sc_w = img.width;
                            let sc_h = img.height;
                            let image = new Konva.Image({
                                image: img,
                                width: sc_w,
                                height: sc_h,
                                x: 180,
                                y: 0,
                                name: 'image2',
                                draggable: false,
                                // opacity: 0.1
                            });
                            layer2.add(image);
                            // layer.draw();
                        },
                        mimeType: "image/jpeg",
                        x: bagRect.x,
                        y: bagRect.y,
                        width: bagRect.width,
                        height: bagRect.height,
                        quality: 0.5, // 0-1
                        pixelRatio: 1, // 
                        imageSmoothingEnabled: false,
                    });


                    layer1.hide();
                    layer2.show();


                } else if (curr_step == OP_STEP.B) {
                    curr_step = OP_STEP.C;
                }





                return false;

            },
            false
        );
    </script>
</body>

</html>